package com.dingreading.cloud.gateway.filters;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.dingreading.cloud.common.util.ErrorCode;
import com.dingreading.cloud.common.util.JsonUtil;
import com.dingreading.cloud.common.util.LoginAuthUtil;
import com.dingreading.cloud.common.util.RedisParam;
import com.dingreading.cloud.gateway.dto.HeadStaffDto;
import com.dingreading.cloud.gateway.service.AdminRoleStaffService;
import com.dingreading.cloud.gateway.service.HeadStaffService;
import com.dingreading.cloud.gateway.util.MonoUtil;
import com.dingreading.cloud.gateway.util.redis.RedisService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.URI;
import java.util.Arrays;
import java.util.List;

/***
 * 总部员工鉴权
 */
@Component
public class AdminAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AdminAuthGatewayFilterFactory.Config> {

    @Resource
    private RedisService redisService;
    @Resource
    private HeadStaffService headStaffService;
    @Resource
    protected AdminRoleStaffService roleStaffService;

    public static AdminAuthGatewayFilterFactory util;

    @PostConstruct
    public void init() {
        util = this;
    }


    public AdminAuthGatewayFilterFactory() {
        super(AdminAuthGatewayFilterFactory.Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("value");
    }

    @Override
    public GatewayFilter apply(AdminAuthGatewayFilterFactory.Config config) {
        return (exchange, chain) -> {
            ServerHttpResponse response = exchange.getResponse();
            ServerHttpRequest request = exchange.getRequest();

            // 登录验证
            Mono<Void> loginAuth = loginAuth(request, response);
            if (loginAuth != null)
                return loginAuth;

            return chain.filter(exchange);
        };
    }


    public static class Config {
        private String value;

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }

    /**
     * 登录验证
     */
    private Mono<Void> loginAuth(ServerHttpRequest request, ServerHttpResponse response) {
        // 获取路由的唯一标识
//        String routeId = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR);

        URI uri = request.getURI();
        if (uri != null) {
            String path = uri.getPath();
            // 跳过验证：总部端登录、获取验证码、swagger
            if (path.contains("/getPicCode") || path.contains("/login") || path.contains("/api-docs"))
                return null;
        }

        String token = LoginAuthUtil.getAuthorization(request.getHeaders());
        if (StringUtils.isBlank(token))
            return MonoUtil.writeResponse(response, ErrorCode.TOKEN_INVALID.getCode(), "无token，请重新登录");

        try {
            // 获取token中的员工uid并查处员工信息
            String headStaffUid = JWT.decode(token).getAudience().get(0);
            if (StringUtils.isBlank(headStaffUid))
                return MonoUtil.writeResponse(response, ErrorCode.TOKEN_INVALID.getCode(), "用户uid不存在，请重新登录");

            HeadStaffDto headStaff = getHeadStaff(headStaffUid);
            if (null == headStaff)
                return MonoUtil.writeResponse(response, ErrorCode.TOKEN_INVALID.getCode(), "用户不存在");
            if (null == headStaff.getEnabled() || !headStaff.getEnabled().equals(1))
                return MonoUtil.writeResponse(response, ErrorCode.TOKEN_INVALID.getCode(), "用户已被禁用，不能登录");

            // 验证 token
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(headStaff.getLastLoginTime())).build();

            jwtVerifier.verify(token);
        } catch (JWTVerificationException e) {
            e.printStackTrace();
            return MonoUtil.writeResponse(response, ErrorCode.TOKEN_INVALID.getCode(), "token失效，请重新登录");
        }

        return null;
    }

    /**
     * 获取总部员工信息
     */
    public static HeadStaffDto getHeadStaff(String uid) {
        HeadStaffDto staff = null;
        String json = (String) util.redisService.get(RedisParam.HEAD_STAFF + uid);
        if (StringUtils.isBlank(json)) {
            staff = util.headStaffService.dtoGetByUid(uid);
            if (staff != null) {
                List<String> identifyList = util.roleStaffService.identifyListByStaffUid(staff.getUid());
                if (CollectionUtils.isNotEmpty(identifyList)) {
                    staff.setIdentifyList(identifyList);
                }
                util.redisService.set(RedisParam.HEAD_STAFF + uid, JsonUtil.toJsonString(staff), RedisParam.HOUR_TIME);
            }
        } else {
            staff = JSONObject.parseObject(json, HeadStaffDto.class);
        }
        return staff;
    }

}
